package com.yjck.ijpay.utils;


import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;


/**
 * HttpRequestUtil
 *
 * @author jiucai created at 2018-08-27 13:37
 * @version 1.0.0
 **/
@Slf4j
public class HttpRequestUtil {

    protected static OkHttpClient client;

    public static final String CHARSET_NAME = "UTF-8";

    public static final MediaType PROTO_BUF = MediaType.parse("application/x-protobuf");
    public static final MediaType JSON = MediaType
    .parse("application/json; CHARSET=" + CHARSET_NAME);
    public static final MediaType BINARY = MediaType.parse("application/octet-stream");
    public static final MediaType FORM = MediaType.parse("application/x-www-form-urlencoded");


    protected static int CONNECT_TIMEOUT = 3000;
    protected static int MAX_CONNECT = 1000;
    protected static int KEEP_ALIVE_MINUTES = 10;

    protected HttpRequestUtil() {

    }


    public static OkHttpClient getClient() {
        if (null == client) {
            ConnectionPool pool = new ConnectionPool(MAX_CONNECT, KEEP_ALIVE_MINUTES,
            TimeUnit.MINUTES);

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS);
            builder.writeTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS);
            builder.readTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS);
            builder.retryOnConnectionFailure(true);
            builder.connectionPool(pool);

            log.info("init pool with maxConnect: {}", MAX_CONNECT);

            client = initClient(builder);
        }

        return client;
    }

    public static void setParam(int connectTimeout, int maxConnect, int keepAliveMinutes) {
        CONNECT_TIMEOUT = connectTimeout;
        MAX_CONNECT = maxConnect;
        KEEP_ALIVE_MINUTES = keepAliveMinutes;
    }

    public static OkHttpClient initClient(OkHttpClient.Builder builder) {
        client = builder.build();
        return client;
    }

    public static OkHttpClient initClient() {
        client = new OkHttpClient();
        return client;
    }

    public static Response postJson(String url, String jsonStr, Map<String, String> headers)
    throws IOException {
        return post(url, JSON, jsonStr.getBytes(CHARSET_NAME), headers);
    }

    public static Response postProtobuf(String url, byte[] content, Map<String, String> headers)
    throws IOException {
        return post(url, PROTO_BUF, content, headers);
    }


    public static Response postJson(String url, String jsonStr) throws IOException {
        return post(url, JSON, jsonStr.getBytes(CHARSET_NAME), null);
    }

    public static Response postProtobuf(String url, byte[] content) throws IOException {
        return post(url, PROTO_BUF, content, null);
    }

    protected static Response doRequest(String url, MediaType mediaType, byte[] content,
                                        Map<String, String> headers, Map<String, String> formData)
    throws IOException {
        long start = System.currentTimeMillis();
        log.debug(">>> requestUrl-{}: {}", Thread.currentThread().getId(), url);

        RequestBody body = null;

        Request.Builder reqBuilder = new Request.Builder()
        .url(url);

        if (null != headers) {
            for (Entry<String, String> entry : headers.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                reqBuilder.header(key, value);
            }
        }

        reqBuilder.header("Connection", "keep-alive");

        if (null != mediaType) {

            reqBuilder.header("Content-Type", mediaType.toString());
            if (FORM.equals(mediaType)) {
                FormBody.Builder formBuilder = new FormBody.Builder();
                for (Entry<String, String> entry : formData.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    formBuilder.addEncoded(key, value);
                    log.debug(">>> postForm-{}: {}:{}", Thread.currentThread().getId(), key, value);
                }

                body = formBuilder.build();

            } else if (null != content) {
//                body = RequestBody.create(content, mediaType);

                /**<pre>
                 *  在spring 2.2.x 未升级 okhttp 到 4.x 之前优先用过期方法保证兼容性
                 *
                 *  否则需要在使用本 cm-common 包的工程属性加入:
                 *
                 *  <okhttp3.version>4.2.2</okhttp3.version>
                 *
                 *  覆盖spring parent 里面的定义
                 *
                 *
                 * </pre>
                 */
                body = RequestBody.create(mediaType, content);

            }
        }

        if (null != body) {
            reqBuilder.header("Content-Length", String.valueOf(body.contentLength()));
            reqBuilder.post(body);
        }

        Request request = reqBuilder.build();

        for (Entry<String, List<String>> entry : request.headers().toMultimap().entrySet()) {
            String key = entry.getKey();
            List<String> value = entry.getValue();
            log.debug(">>> requestHeader-{}: {} = {}", Thread.currentThread().getId(), key, value);
        }

        if (null != body) {
            log.debug(">>> postingBody-{}...", Thread.currentThread().getId());
        }

        Response response = getClient().newCall(request).execute();

        if (null != response) {

            for (Entry<String, List<String>> entry : response.headers().toMultimap().entrySet()) {
                String key = entry.getKey();
                List<String> value = entry.getValue();
                log.debug("<<< responseHeader-{}: {} = {}", Thread.currentThread().getId(), key,
                value);
            }
        }

        log.debug("<<< responseTimeCost-{}: {} ms", Thread.currentThread().getId(),
        System.currentTimeMillis() - start);

        return response;
    }


    public static Response post(String url, MediaType mediaType, byte[] content,
                                Map<String, String> headers)
    throws IOException {
        return doRequest(url, mediaType, content, headers, null);
    }

    public static Response post(String url) throws IOException {

        return post(url, null);
    }

    public static Response post(String url, Map<String, String> headers) throws IOException {

        return post(url, headers, new HashMap<>());
    }

    public static Response post(String url, Map<String, String> headers, Map<String, String> form)
    throws IOException {

        return doRequest(url, FORM, null, headers, form);
    }

    public static Response post(String url, Map<String, String> headers, byte[] postData)
    throws IOException {

        return post(url, BINARY, postData, headers);
    }


    public static Response get(String url, Map<String, String> headers) throws IOException {

        return doRequest(url, null, null, headers, null);

    }

    public static Response get(String url) throws IOException {

        return get(url, null);

    }


    public static void main(String[] args) throws Exception {

        Response res= HttpRequestUtil.get("https://restapi.amap.com/v3/geocode/regeo?key=f476e3327095110419a68427321e8231&poitype=&radius=&extensions=base&batch=false&roadlevel=0&location="+"113.619603,34.775619");

        String result = res.body().string();

        System.out.println(result);


    }

}
